package top.superflow.flow.runtime.mapper

import top.superflow.exception.Exceptable
import top.superflow.lang.StringUtils
import top.superflow.utils.regex.RegexUtils

import scala.beans.BeanProperty
import scala.collection.mutable

class MapperSyntaxPatterns extends Exceptable{

  @BeanProperty
  var patterns: Map[String, MapperPatternConfig] = _

  @BeanProperty
  var splitter: MapperSyntaxSplitter = _

  private val parsedPatterns: mutable.Map[String, String] = mutable.Map()

  def init: Unit = {
    if (!parsedPatterns.isEmpty) {
      return
    }

    for ((patternName, rawPattern) <- patterns) {

      val aliasRegex = generateRegexForAlias(rawPattern.getAlias, patternName)

      var parseRegex = replaceEntityHolder(rawPattern.getPattern, StringUtils.DOLLAR + patternName, aliasRegex)

      parseRegex = replaceRouteNameHolder(parseRegex, MapperSyntaxPatterns.ROUTE_NAME_HOLDER, MapperSyntaxPatterns.ROUTE_NAME_PATTERN)

      parseRegex = replaceSplitter(parseRegex)

      parsedPatterns += (patternName -> parseRegex)
    }

  }

  private def replaceSplitter(pattern : String) : String = {
    StringUtils.replaceOnce(pattern, MapperSyntaxPatterns.SPLITTER_HOLDER, RegexUtils.escape(this.splitter.getSign))
  }

  private def replaceEntityHolder(pattern : String, entityHolder:String, aliasRegex : String) : String = {

    StringUtils.replaceOnce(pattern, entityHolder, aliasRegex)
  }

  private def replaceRouteNameHolder(pattern : String, routeNameHolder:String, aliasRegex : String) : String = {

    StringUtils.replaceOnce(pattern, routeNameHolder, aliasRegex)
  }

  private def generateRegexForAlias(aliases : Array[String], patternName: String) : String = {
    val sbd = new StringBuilder()

    sbd.append("(")
    for(alias <- aliases){
      sbd.append(alias)
      sbd.append("|")
    }

    sbd.append(patternName)

    sbd.append(")")

    sbd.toString()


  }

  def getParsedPatterns: Map[String, String] = {
    if(parsedPatterns.isEmpty){
      throwRequestUnsupportedException("Please invocate init method before using it.")
    }
    parsedPatterns.toMap
  }
}

object MapperSyntaxPatterns {

  private final val SPLITTER_HOLDER = "$splitter"

  private final val ROUTE_NAME_HOLDER = "$route"

  private final val ROUTE_NAME_PATTERN = "\\w+"
}
